package com.miyu.common.utils.aop;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * web控制器aop
 * @author miyu
 * @date 2022/11/01
 */
@Aspect
@Component
@Slf4j
public class WebControllerAop {
    @Pointcut("execution(* com.miyu..*.controller..*.*(..))")
    public void executeService(){}
    /**
     * 后置异常通知
     * 定义一个名字，该名字用于匹配通知实现方法的一个参数名，当目标方法抛出异常返回后，将把目标方法抛出的异常传给通知方法；
     * throwing 限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知，否则不执行，
     *   对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。
     * @param joinPoint
     * @param exception
     */
    @AfterThrowing(value = "executeService()",throwing = "exception")
    public void doAfterThrowingAdvice(JoinPoint joinPoint,Throwable exception){
        //目标方法名：
        if(exception instanceof NullPointerException){
            log.info("controller发生了空指针异常!!!!!");
        }
    }
    /**
     * 环绕通知：
     *  环绕通知非常强大，可以决定目标方法是否执行，什么时候执行，执行时是否需要替换方法参数，执行完毕是否需要替换返回值。
     *  环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
     */
    @Around("executeService()")
    public Object  doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
        Date beginTime = DateUtil.date();;
        Object proceed = null;
        try {
            //obj之前可以写目标方法执行前的逻辑
            proceed= proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        // 执行时长(毫秒)
        Date endTime = DateUtil.date();
        //日志处理存储
        ApiLogInfo.ApiLogCache(proceedingJoinPoint,proceed,beginTime,endTime);
        return proceed;
     }
}
